<script setup lang="ts">
import { onMounted, onUnmounted, ref, shallowRef } from 'vue'
import { Scene, PerspectiveCamera, SphereGeometry, MeshStandardMaterial, Mesh, PlaneGeometry, AmbientLight, DirectionalLight, WebGLRenderer, OrthographicCamera, SpotLight, Vector3 } from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { GUI, GUIController } from 'dat.gui'

const contentRef = ref<HTMLCanvasElement>()
const renderer = shallowRef<WebGLRenderer>(new WebGLRenderer())
const orbitControls = shallowRef<OrbitControls>()
const scene = new Scene()
const camera = shallowRef<PerspectiveCamera>()
const guiControllers = ref<GUIController[]>([])
const gui = new GUI()
const material = new MeshStandardMaterial()

// 创建球体
const sphereGeometry = new SphereGeometry(1, 20, 20)
const mesh = new Mesh(sphereGeometry, material)
scene.add(mesh)

// 创建平面
const planeGeometry = new PlaneGeometry(50, 50)
const planeMesh = new Mesh(planeGeometry, material)
planeMesh.position.set(0, -1, 0)
planeMesh.rotation.x = -Math.PI / 2
scene.add(planeMesh)

// 创建灯光-环境光
const light = new AmbientLight('#ffffff', 0.5)
scene.add(light)
const spotLight = new SpotLight('#ffffff', 0.5)
spotLight.position.set(5, 5, 5)
scene.add(spotLight)

const render = () => {
  if (camera.value) {
    orbitControls.value?.update()
    renderer.value?.render(scene, camera.value)
  }
  requestAnimationFrame(render)
}

onMounted(() => {
  if (contentRef.value) {
    camera.value = new PerspectiveCamera(50, contentRef.value.clientWidth / contentRef.value.clientHeight)
    camera.value.position.set(0, 30, 40)
    scene.add(camera.value)
    contentRef.value.appendChild(renderer.value.domElement)
    renderer.value.setSize(contentRef.value?.clientWidth, contentRef.value?.clientHeight)

    orbitControls.value = new OrbitControls(camera.value, renderer.value.domElement)
    orbitControls.value.enableDamping = true

    // 1. 渲染器阴影选项打开
    renderer.value.shadowMap.enabled = true
    // 2. 平行光投射阴影
    spotLight.castShadow = true
    // 3. 物体投射阴影
    mesh.castShadow = true
    // 4. 平面接收阴影
    planeMesh.receiveShadow = true

    // 设置阴影模糊度
    spotLight.shadow.radius = 20
    // 设置阴影贴图分辨率
    spotLight.shadow.mapSize.set(2048, 2048)

    spotLight.target = mesh
    spotLight.angle = Math.PI / 3
    spotLight.penumbra = 0

    // renderer.value.physicallyCorrectLights = true
    // spotLight.decay = 1

    gui.add<any>(mesh.position, 'x').min(0).max(20).step(0.1)
    gui
      .add<any>(spotLight, 'angle')
      .min(0)
      .max(Math.PI / 2)
      .step(0.01)

    gui.add<any>(spotLight, 'distance').min(10).max(50).step(0.01)
    gui.add<any>(spotLight, 'penumbra').min(0).max(1).step(0.01)
    gui.add<any>(spotLight, 'decay').min(0).max(5).step(0.01)

    render()
  }
})

onUnmounted(() => {
  gui.destroy()
})

window.addEventListener('resize', () => {
  if (contentRef.value && camera.value) {
    console.log('resize')
    camera.value.aspect = contentRef.value.clientWidth / contentRef.value.clientHeight
    camera.value.updateProjectionMatrix()

    renderer.value.setSize(contentRef.value?.clientWidth, contentRef.value?.clientHeight)
    renderer.value.setPixelRatio(window.devicePixelRatio)
  }
})
</script>

<template>
  <div class="base-spot-light-shadow" ref="contentRef"></div>
</template>

<style lang="scss" scoped>
.base-spot-light-shadow {
  width: 100%;
  height: 100%;
}
</style>
